/**
* Oxide
*
* Copyright (c) 2011 Dinosaur Kick Pty Ltd, All rights reserved.
*
* This source code is made available under the "Modified BSD" licensing arrangement.
* See license.txt for details.
*/
// ----------------------------------------------------------------------------
#include <boost/preprocessor.hpp>
// ----------------------------------------------------------------------------
#ifndef O2_COALESCE_INC
#define O2_COALESCE_INC
namespace o2 {
// ----------------------------------------------------------------------------

#ifndef O2_COALESCE_ARITY
#define O2_COALESCE_ARITY 10
#endif

/**
* Yields the first non-void type in the parameter list.
*
* Example:
*
* coalesce<void, void, int>::type -> resolves to "int"
* coalesce<void, void>::type -> results in a compile-time error because ::type is not defined in this case.
*/
template <BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(O2_COALESCE_ARITY, typename T, void)>
struct coalesce
{
	typedef T0 type;
};

// Define the specialisations ...
#define O2_COALESCE_SPECIALIZATIONS(z, n, x) \
	template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
	struct coalesce<BOOST_PP_ENUM_PARAMS(BOOST_PP_SUB(O2_COALESCE_ARITY, n), void BOOST_PP_INTERCEPT), BOOST_PP_ENUM_PARAMS(n, T)> \
	{ \
		typedef T0 type; \
	};

BOOST_PP_REPEAT_FROM_TO(1, O2_COALESCE_ARITY, O2_COALESCE_SPECIALIZATIONS, 0)

/**
* Define the specialization that handles all-void types.
* Note that there is no typedef available, generating a compile error when all types are void.
*/
template <>
struct coalesce<BOOST_PP_ENUM_PARAMS(O2_COALESCE_ARITY, void BOOST_PP_INTERCEPT)>
{	
};

#undef O2_COALESCE_SPECIALIZATIONS

// ----------------------------------------------------------------------------
} // namespace o2
#endif // O2_COALESCE_INC
// ----------------------------------------------------------------------------
